package com.province.platform.core.classLoader;

import com.province.platform.common.enums.CommonErrorCode;
import com.province.platform.common.exception.PlatformException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class JarLoader extends URLClassLoader {
    public JarLoader(String[] paths) {
        this(paths, JarLoader.class.getClassLoader());
    }

    public JarLoader(String[] paths, ClassLoader parent) {
        super(getURLs(paths), parent);
    }

    private static URL[] getURLs(String[] paths) {
        Validate.isTrue(Objects.nonNull(paths) && paths.length != 0, "jar包路径不能为空");

        List<String> dirs = new ArrayList<>();
        for (String path: paths) {
            dirs.add(path);
            collectDirs(path, dirs);
        }

        List<URL> urls = new ArrayList<>();
        for (String path: dirs) {
            urls.addAll(doGetURLs(path));
        }

        return urls.toArray(new URL[0]);
    }

    private static List<URL> doGetURLs(final String path) {
        Validate.isTrue(StringUtils.isNotBlank(path), "jar包路径不能为空");

        File jarPath = new File(path);

        Validate.isTrue(jarPath.exists() && jarPath.isDirectory(), "jar包路径必须存在且为目录");

        File[] allJars = new File(path).listFiles(pathname -> pathname.getName().endsWith(".jar"));
        List<URL> jarURLs = new ArrayList<>(allJars.length);

        for (File jarFile: allJars) {
            try {
                jarURLs.add(jarFile.toURI().toURL());
            } catch (Exception e) {
                throw PlatformException.asPlatformException(CommonErrorCode.PLUGIN_INIT_ERROR, "系统加载jar包出错", e);
            }
        }

        return jarURLs;
    }

    private static void collectDirs(String path, List<String> dirs) {
        if (StringUtils.isBlank(path)) {
            return;
        }

        File current = new File(path);
        if (!current.exists() || !current.isDirectory()) {
            return;
        }

        for (File child: current.listFiles()) {
            if (!child.isDirectory()) {
                continue;
            }

            dirs.add(child.getAbsolutePath());
            collectDirs(child.getAbsolutePath(), dirs);
        }
    }
}
